""" 针对openharmony组织的统计方法特性化模块

通过扩展VersionInfoHandler接口，实现对版本的特性定义
通过扩展ReportInfoHandler接口，实现对报告的特性定制
"""
import collections
import logging
import os
import re

from code_metric.config import get_org_dynamic_config, init_global_config_setting
from code_metric.codes import Organization, Repo, Version, VersionInfoHandler
from code_metric.metric import ReportInfoHandler, DefaultRIHandler
from code_metric.utils import get_xml_response_from_url, write_as_excel, get_date, read_excel_to_dict_list
from code_metric.utils_str import parse_owner_and_repo_name_to_repo_url, form_abs_name_for_version_repos_info_file, \
    form_abs_name_for_repo_cloc_raw_file, form_abs_name_for_version_code_line_report, parse_str_without_punctuation

CONFIG = init_global_config_setting()
BASE_DIR = os.path.dirname(os.path.abspath(__file__))


class OHVersionInfoHandler(VersionInfoHandler):

    def __init__(self, version_name='master', owner_name='openharmony'):
        self.org_name = owner_name
        self.version_name = version_name
        self.version_repos_info_file = form_abs_name_for_version_repos_info_file(owner_name, version_name)
        self._version_config_dict = get_org_dynamic_config(owner_name)
        assert version_name in self._version_config_dict, f'请于config.toml, 配置{owner_name}版本{version_name}的相关信息'

    def get_version_released_time(self):
        version_time = self._version_config_dict[self.version_name]['time']
        if version_time == 'now':
            version_time = get_date()
        return version_time

    def get_version_repos_ref(self):
        ref_name = self._version_config_dict[self.version_name]['ref']
        ref_type = self._version_config_dict[self.version_name]['ref_type']
        return ref_name, ref_type

    def get_version_repos_info_file(self):
        return self.version_repos_info_file

    def init_version_repos_info_file(self):
        self._init_repos_info_excel()
        return self.version_repos_info_file

    def _init_repos_info_excel(self, renew_now=False):
        if renew_now or not os.path.exists(self.version_repos_info_file):
            self._generate_repos_info_excel_for_version()
        return self.version_repos_info_file

    def _generate_repos_info_excel_for_version(self):
        manifest_type = self._version_config_dict[self.version_name]['manifest']
        ref = self.get_version_repos_ref()[0]
        output_list = []
        if manifest_type == 'just_all_repo':
            Organization(self.org_name).init_repos_info_excel()
            return
        if manifest_type == 'ohos_and_chipsets':
            request_url_list = self._get_ohos_and_chipsets_xml_url_list(ref)
            for request_url in request_url_list:
                output_list.extend(self._get_repos_from_xml(request_url))
        if manifest_type == 'default':
            request_url = "https://gitee.com/openharmony/manifest/raw/" + ref + "/default.xml"
            output_list.extend(self._get_repos_from_xml(request_url))
        write_as_excel(self.version_repos_info_file, output_list, columns_order=['仓库名称', '仓库链接'])

    @staticmethod
    def _get_ohos_and_chipsets_xml_url_list(ref):
        request_url_list = []
        request_url = "https://gitee.com/openharmony/manifest/raw/" + ref + "/ohos/ohos.xml"
        request_url_list.append(request_url)
        request_url = "https://gitee.com/openharmony/manifest/raw/" + ref + "/chipsets/all.xml"
        root = get_xml_response_from_url(request_url)
        for include_node in root.findall('include'):
            chipset_name = include_node.attrib['name']
            chipset_url = "https://gitee.com/openharmony/manifest/raw/" + ref + "/" + chipset_name
            request_url_list.append(chipset_url)
        return request_url_list

    @staticmethod
    def _get_repos_from_xml(request_url):
        repo_url_list = []
        root = get_xml_response_from_url(request_url)
        for project_node in root.findall('project'):
            repo_name = project_node.attrib['name']
            org_name = 'openharmony-retired' if 'remote' in project_node.attrib else 'openharmony'
            repo_url_list.append({"仓库名称": repo_name,
                                  "仓库链接": parse_owner_and_repo_name_to_repo_url(org_name, repo_name)})
        return repo_url_list


class OHReportInfoHandler(DefaultRIHandler):
    REPO_3RD_FILE_DIR_DICT = collections.defaultdict(list)
    REPO_MAIL_HOST_DICT = collections.defaultdict(dict)

    def __init__(self, org_name='openharmony', no_third=False, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._version_config_dict = get_org_dynamic_config(org_name)
        self._no_third = no_third

    def is_repo_need_to_count(self, repo) -> bool:
        if self._is_repo_need_to_ignore(repo):
            return False
        if self._no_third and ('third_party' in repo.name or
                               repo.name in ('kernel_linux_5.10', 'kernel_linux_patches', 'kernel_linux')):
            logging.info('三方库，跳过统计: ' + repo.name)
            return False
        return True

    @staticmethod
    def _is_repo_need_to_ignore(repo):
        if repo.ref in ('OpenHarmony-1.0', 'OpenHarmony_release_v1.1.0'):
            return False
        if repo.name in ('kernel_linux_4.19', 'third_party_Linux_Kernel'):
            logging.info('重复的三方linux_kernel库，跳过统计: ' + repo.name)
            return True
        return False

    def is_file_need_to_count(self, file) -> bool:
        if self._no_third and self._is_file_third_party(file):
            logging.info('三方文件，跳过统计: ' + file.name)
            return False
        return True

    def _is_file_third_party(self, file):
        is_third_party_file = True
        _copyright = file.get_copyright()
        _repo_name = file.repo.name

        if _repo_name in ['docs', 'arkcompiler_ets_runtime']:
            is_third_party_file = False
        elif self._is_file_copyright_no_3rd_based_on_config_file(file.get_copyright()):
            is_third_party_file = False

        if _repo_name == 'device_board_isoftstone' and \
                ('allwinner' in _copyright or _copyright == CONFIG['no_copyright']):
            is_third_party_file = True
        elif self._is_file_path_3rd_based_on_tool_file(file):
            is_third_party_file = True

        return is_third_party_file

    def _is_file_copyright_no_3rd_based_on_config_file(self, file_copyright):
        if file_copyright == CONFIG['no_copyright']:
            return True
        not_3rd_com = self._version_config_dict['config']['not_3rd_company_list']
        return any(company_name in file_copyright for company_name in not_3rd_com)

    def _is_file_path_3rd_based_on_tool_file(self, file):
        if 'third_party' in file.name:
            return True
        if not self.REPO_3RD_FILE_DIR_DICT:
            self._init_3rd_file_dir_dict()
        repo_3rd_file_dir_list = self.REPO_3RD_FILE_DIR_DICT[(file.repo.name, file.repo.ref)]
        return any(file_3rd_dir in file.name for file_3rd_dir in repo_3rd_file_dir_list)

    def _init_3rd_file_dir_dict(self):
        repo_3rd_file_dir_file = os.path.join(BASE_DIR, CONFIG['tool_path'],
                                              self._version_config_dict['config']['file_owner_mod_file'])
        repo_3rd_file_dir_info_list = read_excel_to_dict_list(repo_3rd_file_dir_file)
        for record in repo_3rd_file_dir_info_list:
            id_tuple = (record['repo_name'], record['ref'])
            self.REPO_3RD_FILE_DIR_DICT[id_tuple].append(record['third_party_file_dir'])

    def modify_file_info(self, file):
        self._modify_file_copyright(file)

    def _modify_file_copyright(self, file):
        if file.type == '.json':
            file._copyright = CONFIG['no_copyright']
            return
        if file.get_copyright() != CONFIG['no_copyright']:
            return
        try:
            with open(file.path, 'r', encoding='UTF-8', errors='ignore') as f:
                for line in f.readlines():
                    if file._copyright != CONFIG['no_copyright']:
                        break
                    line = line.lower()
                    if 'spdx-license-identifier: gpl-2.0' in line:
                        file._copyright = 'SPDX-License-Identifier: GPL-2.0'
                    elif 'licensed to the apache software foundation (asf)' in line:
                        file._copyright = 'Licensed to the Apache Software Foundation (ASF)'
                    elif self._is_copyright_without_c_count(file, line):
                        file._copyright = re.search(r'c.*$', line).group()
        except Exception as message:
            logging.error('打开文件，尝试判断版权时，发生异常：' + repr(message))

    @staticmethod
    def _is_copyright_without_c_count(file, line):
        if 'copyright' not in line:
            return False
        if file.repo.name == 'device_soc_rockchip' and 'rockchip' in line:
            return True
        if file.repo.ref in ['OpenHarmony-1.0'] \
                and r'vendor_huawei_hdf\sample\platform\uart' in file.path:
            return True
        if file.repo.ref in ['OpenHarmony_release_v1.1.0', 'OpenHarmony-2.0-Canary'] \
                and r'vendor_huawei_hdf\sample\platform\spi' in file.path \
                or r'vendor_huawei_hdf\sample\platform\uart' in file.path \
                or r'vendor_huawei_hdf\sample\platform\gpio' in file.path:
            return True
        if file.repo.ref in ['OpenHarmony-v3.2-Release'] \
                and r'vendor_unionman\unionpi_tiger\sample' in file.path \
                or r'drivers_peripheral\codec\hal' in file.path \
                or r'device_soc_st\stm32f407zg\uniproton\board\common\ STM32 F4x7_ETH_Driver\src' in file.path:
            return True
        return False

    def modify_author_info(self, author):
        self._modify_email_without_punctuation(author)
        self._modify_email_host_from_default_setting(author)
        self._modify_email_host_from_config_file(author)
        author._company = ''

    @staticmethod
    def _modify_email_without_punctuation(author):
        punc_to_remove = ['‘', '’', '“', '”', '[', ']', '（', '）']
        author.email = parse_str_without_punctuation(author.email, punc_to_remove)

    def _modify_email_host_from_default_setting(self, author):
        email = author.email
        host = author.get_email_host()
        if email.endswith('.local') or email.endswith('.localdomain'):
            author._email_host = '@XXX.localdomain'
        elif self._is_author_employed_by_huawei(email, host):
            author._email_host = '@huawei.com'

    @staticmethod
    def _is_author_employed_by_huawei(email, host):
        if 'huawei' in email or '@h-partners' in email or '@h-parners.com' in email:
            return True
        if email in ['pssea', 'limeng151', 'liemng151', '123', 'xlei1030']:
            return True
        if host in ['@hisilicon.com', '@h-partners.com', '@huawe.com', '@huaweri.com', '@hauwei.com']:
            return True
        return False

    def _modify_email_host_from_config_file(self, author):
        if not self.REPO_MAIL_HOST_DICT:
            self._init_mail_host_dict()
        repo_name = author.file.repo.name
        ref = author.file.repo.ref
        mail_to_new_host_dict = self.REPO_MAIL_HOST_DICT[(repo_name, ref)]
        author._email_host = mail_to_new_host_dict.get(author.email, author._email_host)

    def _init_mail_host_dict(self):
        repo_mail_host_file = os.path.join(BASE_DIR, CONFIG['tool_path'],
                                           self._version_config_dict['config']['email_host_mod_file'])
        repo_mail_host_info_list = read_excel_to_dict_list(repo_mail_host_file)
        for record in repo_mail_host_info_list:
            id_tuple = (record['repo_name'], record['ref'])
            self.REPO_MAIL_HOST_DICT[id_tuple][record['email']] = record['new_mail_host']


if __name__ == '__main__':
    pass
